package com.johnny.springai.toolsfunction.service;

import org.springframework.ai.chat.messages.AssistantMessage.ToolCall;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.ai.tool.method.MethodToolCallback;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;

@Service
public class ToolService {

    @Autowired
    private TicketService ticketService;

    //@Tool 告诉大模型提供了什么工具
    @Tool(description = "退票")
    @PreAuthorize("hasRole('ADMIN')")
    public String cancel(
            //@ToolParam 告诉大模型参数的用途
            @ToolParam(description = "预定号，可以是纯数字") String ticketNumber,
            @ToolParam(description = "姓名（必须是真实姓名，严谨用其他信息代替，如缺失请传null）") String name) {

        //当前登录用户名
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();

        //先根据参数先查询信息，如果存在则指向退票业务逻辑
        return userName + ticketService.cancel(ticketNumber, name);
    }

    @Tool(description = "获取指定位置天气,根据位置自动推算经纬度")
    public String getAirQuality(@ToolParam(description = "纬度") double latitude,
                                @ToolParam(description = "经度") double longitude) {
        return "天晴";
    }

    /**
     * 模拟从数据库中动态根据当前用户角色读取tools
     *
     * @param toolService 不能自己new，自己new不能解析依赖注入
     * @return
     */
    public List<ToolCallback> getToolCallList(ToolService toolService) {

        //todo 在数据库中设置一张权限对应tool的表 并根据当前登录用户的权限从数据库中获取相应的数据。。。代码省略
        //拿一个tool为例
        //1.获取tool处理方式，通过反射获取对应的方法，已经对于的参数
        Method method = ReflectionUtils.findMethod(ToolService.class, "cancel", String.class, String.class);
        //2.构建tool定义信息 动态配置的方式 @Tool @ToolParam 都无效
        ToolDefinition toolDefinition = ToolDefinition.builder()
                .name("cancel")
                .description("退票") //对应@ToolDescription
                //对应@ToolParam
                .inputSchema("""
                        {
                            "type": "object",
                            "properties": {
                                "ticketNumber": {
                                    "type": "string",
                                    "description": "预定号，可以是纯数字"
                                },
                                "name": {
                                    "type": "string",
                                    "description": "真实人名"
                                }
                            },
                            "required": ["ticketNumber", "name"]
                        }
                """)
                .build();
        //一个toolCallBack 对应一个tool
        ToolCallback toolCallback = MethodToolCallback.builder()
                .toolDefinition(toolDefinition)
                .toolMethod(method)
                .toolObject(toolService)
                .build();
        return List.of(toolCallback);
    }
}
